package com.xbongbong.saas.help;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.ConfigConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.model.PaasEsModel;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.MoneyUtil;
import com.xbongbong.pro.enums.errorcodes.InvoiceErrorCodeEnum;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.InvoiceConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.InvoiceRelationshipEntity;
import com.xbongbong.saas.domain.entity.ext.ContractEntityExt;
import com.xbongbong.saas.domain.entity.ext.PaymentEntityExt;
import com.xbongbong.saas.domain.entity.ext.PaymentSheetEntityExt;
import com.xbongbong.saas.enums.RedundantTemplateTypeEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.InvoiceEnum;
import com.xbongbong.saas.enums.business.PaymentEnum;
import com.xbongbong.saas.enums.business.PaymentRelationshipEnum;
import com.xbongbong.saas.enums.business.PaymentSheetEnum;
import com.xbongbong.saas.model.ContractModel;
import com.xbongbong.saas.model.InvoiceRelationshipModel;
import com.xbongbong.saas.model.PaymentModel;
import com.xbongbong.saas.model.PaymentSheetModel;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.util.InvoiceUtil;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getDoubleFromFormData;
import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getDoubleOrDefaultFromFormData;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @author 吴峰
 * @date 2021/07/19 11:05
 */
@Component
public class SaasInvoiceHelp {

    private static final Logger LOGGER = LoggerFactory.getLogger(SaasInvoiceHelp.class);

    @Resource
    private PaymentSheetModel paymentSheetModel;
    @Resource
    private ContractModel contractModel;
    @Resource
    private PaymentModel paymentModel;
    @Resource
    private InvoiceRelationshipModel invoiceRelationshipModel;
    @Resource
    private EsHelper esHelper;
    @Resource
    private PaasEsModel paasEsModel;

    public Map<String, Object> getRelationMapForJudgeMoney(boolean isHasPaymentSheet, boolean isPrePaymentSheet, boolean isPrePaymentSheetUnion, boolean isHasPayment, String corpid, List<Long> contractIds, List<Long> paymentOrSheetIds) throws XbbException {
        Map<String, Object> relationMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        String type = BasicConstant.CONTRACT;
        Map<String, Object> tempParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        tempParam.put(ParameterConstant.ID_IN, contractIds);
        tempParam.put(ParameterConstant.CORPID, corpid);
        List<ContractEntityExt> contractList = contractModel.findEntitys(tempParam);
        int num = 0;
        Double contractMoney = 0D;
        Double paymentMoney = 0D;
        Double paymentSheetMoney = 0D;
        Map<Long,Double> contractUnInvoiceMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,Double> contractInvoiceMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,Double> paymentInvoiceMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,Double> paymentMoneyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,Double> paymentSheetMoneyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,Double> paymentSheetInvoiceMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,Double> contractTotalMoneyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,Double> paymentTotalMoneyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,Double> paymentSheetTotalMoneyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        //计算合同金额
        for (ContractEntityExt contractEntityExt : contractList) {
            JSONObject dataList = contractEntityExt.getData();
            contractMoney = Arith.add(contractMoney,getDoubleOrDefaultFromFormData(dataList, ContractEnum.AMOUNT.getAttr(), 0D));
            contractTotalMoneyMap.put(contractEntityExt.getId(),getDoubleOrDefaultFromFormData(dataList,ContractEnum.AMOUNT.getAttr(),0D));
            contractUnInvoiceMap.put(contractEntityExt.getId(),getDoubleOrDefaultFromFormData(dataList, ContractEnum.UN_INVOICE_AMOUNT.getAttr(), 0D));
            contractInvoiceMap.put(contractEntityExt.getId(),getDoubleOrDefaultFromFormData(dataList, ContractEnum.INVOICE_AMOUNT.getAttr(), 0D));
            num++;
        }
        relationMap.put("contractNum", num);
        relationMap.put("contractId", contractIds);
        relationMap.put("contractMoney", contractMoney);
        relationMap.put("contractInvoiceMoney",contractInvoiceMap);
        relationMap.put("contractUnInvoiceMoney",contractUnInvoiceMap);
        relationMap.put("contractTotalMoney",contractTotalMoneyMap);
        num = 0;
        if (isHasPayment) {
            tempParam.put(ParameterConstant.ID_IN, paymentOrSheetIds);
            List<PaymentEntityExt> paymentList = paymentModel.findEntitys(tempParam);
            tempParam.remove("ids");
            for (PaymentEntityExt paymentEntityExt : paymentList) {
                JSONObject dataList = paymentEntityExt.getData();
                paymentMoney += getDoubleOrDefaultFromFormData(dataList, PaymentEnum.AMOUNT.getAttr(), 0D);
                paymentMoneyMap.put(paymentEntityExt.getId(),getDoubleOrDefaultFromFormData(dataList, PaymentEnum.AMOUNT.getAttr(), 0D));
                paymentInvoiceMap.put(paymentEntityExt.getId(),getDoubleOrDefaultFromFormData(dataList, PaymentEnum.INVOICE_AMOUNT.getAttr(), 0D));
                paymentTotalMoneyMap.put(paymentEntityExt.getId(),getDoubleOrDefaultFromFormData(dataList,PaymentEnum.AMOUNT.getAttr(),0D));
                num++;
            }
            type = BasicConstant.PAYMENT;
            relationMap.put("paymentId", paymentOrSheetIds);
            relationMap.put("paymentMoney", paymentMoney);
            relationMap.put("paymentMoneyMap",paymentMoneyMap);
            relationMap.put("paymentInvoiceMoney",paymentInvoiceMap);
            relationMap.put("paymentTotalMoney",paymentTotalMoneyMap);
            relationMap.put("paymentNum", num);
        }else {
            relationMap.put("paymentNum", 0);
        }
        if(isHasPaymentSheet){
            tempParam.put(ParameterConstant.ID_IN, paymentOrSheetIds);
            List<PaymentSheetEntityExt> paymentSheetEntityExtList = paymentSheetModel.findEntitys(tempParam);
            for(PaymentSheetEntityExt paymentSheetEntityExt : paymentSheetEntityExtList){
                JSONObject dataList = paymentSheetEntityExt.getData();
                paymentSheetMoney += getDoubleOrDefaultFromFormData(dataList, PaymentSheetEnum.AMOUNT.getAttr(),0D);
                paymentSheetMoneyMap.put(paymentSheetEntityExt.getId(),getDoubleOrDefaultFromFormData(dataList, PaymentSheetEnum.AMOUNT.getAttr(), 0D));
                paymentSheetInvoiceMap.put(paymentSheetEntityExt.getId(),getDoubleOrDefaultFromFormData(dataList, PaymentSheetEnum.INVOICE_AMOUNT.getAttr(), 0D));
                paymentSheetTotalMoneyMap.put(paymentSheetEntityExt.getId(),getDoubleOrDefaultFromFormData(dataList,PaymentSheetEnum.AMOUNT.getAttr(),0D));
                num++;
            }
            type = BasicConstant.PAYMENTSHEET;
            relationMap.put("isPrePaymentSheet",isPrePaymentSheet);
            relationMap.put("isPrePaymentSheetUnion",isPrePaymentSheetUnion);
            relationMap.put("paymentSheetId",paymentOrSheetIds);
            relationMap.put("paymentSheetMoney",paymentSheetMoney);
            relationMap.put("paymentSheetMoneyMap",paymentSheetMoneyMap);
            relationMap.put("paymentSheetInvoiceMoney",paymentSheetInvoiceMap);
            relationMap.put("paymentSheetTotalMoney",paymentSheetTotalMoneyMap);
            relationMap.put("paymentSheetNum",num);
        }else {
            relationMap.put("paymentSheetNum",0);
        }
        relationMap.put("type", type);
        return relationMap;
    }

    public void invoiceAmountJudgment(String corpid, Long invoiceId, Double invoiceMoney, Map<String, Object> relationIdIn, Integer isImport, Integer isCover, Integer isRestore, JSONArray amountDetail) throws XbbException {
        // 总合同金额
        Double totalContractMoney = 0D;
        // 已开金额
        Double alreadyMoney = 0D;
        //合同已开金额
        Double contractAlreadMoney = 0D;
        // 总回款金额
        Double totalPaymentMoney = 0D;
        // 总回款单金额
        Double totalPaymentSheetMoney= 0D;
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put(ParameterConstant.INVOICE_ID, invoiceId);
        param.put(ParameterConstant.CORPID, corpid);
        param.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        // 发票关联表数据
        List<InvoiceRelationshipEntity> relations;
        //非新建的情况
        if (!Objects.equals(invoiceId, 0L)) {
            relations = invoiceRelationshipModel.getByParam(param);
            if (relations.isEmpty()) {
                return;
            }
        }
        param.remove(ParameterConstant.INVOICE_ID);
        param.put(ParameterConstant.IS_CANCEL, BasicConstant.ZERO);
        param.put(ParameterConstant.FLOW_STATUS_IN, Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType()));
        // 判断操作类型和是否合并开票
        Map<String, Object> map = judgeOperationAndMerge(relationIdIn, invoiceId);
        // 是否合并开票
        boolean isMerge = (boolean) map.getOrDefault("isMerge", false);
        // 操作类型
        String operation = map.getOrDefault("operation", "").toString();
        // 类型
        String  type = map.getOrDefault("type", "").toString();
        boolean isPrePaymentSheet = false;
        boolean isPrePaymentSheetUnion = false;
        if(relationIdIn.containsKey(InvoiceConstant.IS_PRE_PAMENT_SHEET)){
            isPrePaymentSheet = (boolean) relationIdIn.get(InvoiceConstant.IS_PRE_PAMENT_SHEET);
        }
        if(relationIdIn.containsKey(InvoiceConstant.IS_PRE_PAYMENT_SHEET_UNION)){
            isPrePaymentSheetUnion = (boolean) relationIdIn.get(InvoiceConstant.IS_PRE_PAYMENT_SHEET_UNION);
        }
        if (!isMerge) {
            // 单次开票需要计算是否超出
            Long paymentId = 0L;
            Long paymentSheetId = 0L;
            List<Map<String, Object>> contractSumMoney = null;
            List<Map<String,Object>> paymentOrSheetSumMoney = null;
            // 回款开票既要确认开票金额是否大于所在合同剩余可开金额,有要判断开票金额是否大于所在回款剩余可开金额;存在合同已开完而回款单未开过等特殊情况
            if (BasicConstant.CONTRACT.equals(type) || BasicConstant.PAYMENT.equals(type) || BasicConstant.PAYMENTSHEET.equals(type) || Objects.equals(isImport,BasicConstant.ONE)) {
                List<Long> contractIds = new ArrayList<>();
                // 新建编辑
                if (InvoiceConstant.NEW.equals(operation) || InvoiceConstant.EDIT.equals(operation)) {
                    if (InvoiceConstant.EDIT.equals(operation)) {
                        param.put("invoiceIdNot", invoiceId);
                    }
                    if(!isPrePaymentSheet) {
                        if (relationIdIn.get(InvoiceConstant.CONTRACT_ID) instanceof List) {
                            contractIds = (List<Long>) relationIdIn.get(InvoiceConstant.CONTRACT_ID);
                        }
                        //关联表合同Id
                        if (contractIds.get(0) > BasicConstant.ZERO) {
                            param.put(InvoiceConstant.CONTRACT_ID, contractIds.get(0));
                        }
                        totalContractMoney = MoneyUtil.parseDouble(relationIdIn.get("contractMoney"));
                        contractSumMoney = invoiceRelationshipModel.getSumMoneyOfContract(param);
                    }
                }
                if (BasicConstant.PAYMENT.equals(type)) {
                    if (operation.equals(InvoiceConstant.NEW) || operation.equals(InvoiceConstant.EDIT)) {
                        if(relationIdIn.get(InvoiceConstant.PAYMENT_ID) instanceof List) {
                            paymentId = ((List<Long>) relationIdIn.get("paymentId")).get(0);
                        }
                        param.put(InvoiceConstant.PAYMENT_ID,paymentId);
                    }
                    totalPaymentMoney = MoneyUtil.parseDouble(relationIdIn.get("paymentMoney"));
                    paymentOrSheetSumMoney = invoiceRelationshipModel.getSumMoneyofPayment(param);
                }else if(BasicConstant.PAYMENTSHEET.equals(type)){
                    if(operation.equals(InvoiceConstant.NEW) || operation.equals(InvoiceConstant.EDIT)){
                        if(relationIdIn.get(InvoiceConstant.PAYMENT_SHEET_ID) instanceof List) {
                            paymentSheetId = ((List<Long>) relationIdIn.get(InvoiceConstant.PAYMENT_SHEET_ID)).get(0);
                        }
                        param.put(InvoiceConstant.PAYMENT_SHEET_ID,paymentSheetId);
                    }
                    totalPaymentSheetMoney = MoneyUtil.parseDouble(relationIdIn.get("paymentSheetMoney"));
                    paymentOrSheetSumMoney = invoiceRelationshipModel.getSumMoneyofPaymentSheet(param);
                }
                //回款所关联的合同已开金额
                if (CollectionsUtil.isEmpty(paymentOrSheetSumMoney)) {
                    alreadyMoney = 0D;
                } else {
                    alreadyMoney = MoneyUtil.parseDouble(paymentOrSheetSumMoney.get(0).get("allMoney"));
                }
            }
            if(!isPrePaymentSheet) {
                if (CollectionsUtil.isEmpty(contractSumMoney)) {
                    contractAlreadMoney = 0D;
                }else {
                    contractAlreadMoney =  MoneyUtil.parseDouble(contractSumMoney.get(0).get("allMoney"));
                }
                if (Arith.sub(invoiceMoney, Arith.sub(totalContractMoney, contractAlreadMoney)) > ConfigConstant.amountAccuracy) {
                    throw new XbbException(InvoiceErrorCodeEnum.APT_ERROR_216001);
                }
            }
            if (BasicConstant.PAYMENT.equals(type)) {
                //如果是回款开票,在判断完开票金额小于合同可开金额后，还需与回款可开金额进行比较
                if (Arith.sub(invoiceMoney, Arith.sub(totalPaymentMoney, alreadyMoney)) > ConfigConstant.amountAccuracy) {
                    throw new XbbException(InvoiceErrorCodeEnum.APT_ERROR_216002);
                }
            }else if(BasicConstant.PAYMENTSHEET.equals(type)){
                if(Arith.sub(invoiceMoney,Arith.sub(totalPaymentSheetMoney,alreadyMoney)) > ConfigConstant.amountAccuracy){
                    throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216022);
                }
            }
        } else {
            Map<Long,Double> contractTotalInvoiceMoneyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<Long,Double> paymentOrSheetTotalInvoiceMoneyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<Long,Double> contractReadyInvoiceMoneyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<Long,Double> paymentOrSheetReadyInvoiceMoneyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            if (BasicConstant.CONTRACT.equals(type)) {
                //新增编辑审批 合同合并开票
                if (InvoiceConstant.EDIT.equals(operation)) {
                    param.put("invoiceIdNot", invoiceId);
                }
                List<Long> contractIds = null;
                int contractIdNum = 0;
                if (relationIdIn.get(InvoiceConstant.CONTRACT_ID) instanceof List) {
                    contractIds = (List<Long>) relationIdIn.get(InvoiceConstant.CONTRACT_ID);
                    param.put("contractIdIn", contractIds);
                    contractIdNum = contractIds.size();
                }
                if (relationIdIn.get(InvoiceConstant.CONTRACT_TOTAL_MONEY) instanceof Map) {
                    contractTotalInvoiceMoneyMap = (Map<Long, Double>) relationIdIn.get(InvoiceConstant.CONTRACT_TOTAL_MONEY);
                }
                //获取已开的发票金额
                getRefIdAndAmount(param, contractReadyInvoiceMoneyMap, InvoiceEnum.CONTRACT_ID);

                if (Objects.equals(isImport, BasicConstant.ONE)) {
                    getCountInvoice(param,relationIdIn, invoiceMoney, InvoiceConstant.CONTRACT_TOTAL_MONEY,isCover);
                }else{
                    if(Objects.equals(isRestore, BasicConstant.ONE)){
                        param.remove("invoiceIdNot");
                        param.put("invoiceId",invoiceId);
                        //作废后还原逻辑，去数据库取金额明细
                        param.put(ParameterConstant.IS_CANCEL, BasicConstant.ONE);
                        List<InvoiceRelationshipEntity> relationshipEntities = invoiceRelationshipModel.findEntitys(param);
                        for(InvoiceRelationshipEntity invoiceRelationshipEntity : relationshipEntities){
                            Long contractId = invoiceRelationshipEntity.getContractId();
                            Double contractInvoice = invoiceRelationshipEntity.getMoney();
                            InvoiceUtil.checkContractInvoiceAmountHandle(contractReadyInvoiceMoneyMap,contractTotalInvoiceMoneyMap,contractId,contractInvoice);
                        }
                    }else {
                        for(int i=0;i<amountDetail.size();i++){
                            JSONObject amountObject = amountDetail.getJSONObject(i);
                            JSONObject contractObject = amountObject.getJSONArray(InvoiceConstant.CONTRACT).getJSONObject(0);
                            Long contractId = contractObject.getLong(BasicConstant.ID);
                            Double contractInvoiceMoney = amountObject.getDouble(InvoiceConstant.INVOICE_AMOUNT);
                            InvoiceUtil.checkContractInvoiceAmountHandle(contractReadyInvoiceMoneyMap,contractTotalInvoiceMoneyMap,contractId,contractInvoiceMoney);
                        }
                    }
                }
            }
            if (BasicConstant.PAYMENT.equals(type)) {
                //如果是回款开票,在判断完开票金额小于合同可开金额后，还需与回款可开金额进行比较
                if (InvoiceConstant.EDIT.equals(operation)) {
                    param.put("invoiceIdNot", invoiceId);
                }
                List<Long> paymentIds = null;
                List<Long> contractIds = null;
                int paymentIdNum = 0;
                if(relationIdIn.get(InvoiceConstant.PAYMENT_ID) instanceof List){
                    paymentIds = (List<Long>) relationIdIn.get(InvoiceConstant.PAYMENT_ID);
                    param.put("paymentIdIn",paymentIds);
                    paymentIdNum = paymentIds.size();
                }
                if(relationIdIn.get(InvoiceConstant.CONTRACT_ID) instanceof List){
                    contractIds = (List<Long>) relationIdIn.get(InvoiceConstant.CONTRACT_ID);
                }
                if(relationIdIn.get(InvoiceConstant.PAYMENT_TOTAL_MONEY) instanceof Map){
                    paymentOrSheetTotalInvoiceMoneyMap = (Map<Long,Double>) relationIdIn.get(InvoiceConstant.PAYMENT_TOTAL_MONEY);
                }
                if(relationIdIn.get(InvoiceConstant.CONTRACT_TOTAL_MONEY) instanceof Map){
                    contractTotalInvoiceMoneyMap = (Map<Long,Double>) relationIdIn.get(InvoiceConstant.CONTRACT_TOTAL_MONEY);
                }
                //获取已开的发票金额
                param.remove("paymentIdIn");
                param.put("contractIdIn",contractIds);
                getRefIdAndAmount(param,contractReadyInvoiceMoneyMap,InvoiceEnum.CONTRACT_ID);
                param.put("paymentIdIn",paymentIds);
                getRefIdAndAmount(param,paymentOrSheetReadyInvoiceMoneyMap,InvoiceEnum.PAYMENT_ID);
                if(Objects.equals(isImport,BasicConstant.ONE)){
                    //批量走 这个
                    getCountInvoice(param,relationIdIn,invoiceMoney,InvoiceConstant.PAYMENT_TOTAL_MONEY,isCover);
                }else {
                    if(Objects.equals(isRestore, BasicConstant.ONE)){
                        param.remove("invoiceIdNot");
                        param.put("invoiceId",invoiceId);
                        //作废后还原逻辑，去数据库取金额明细
                        param.put(ParameterConstant.IS_CANCEL, BasicConstant.ONE);
                        List<InvoiceRelationshipEntity> relationshipEntities = invoiceRelationshipModel.findEntitys(param);
                        for(InvoiceRelationshipEntity invoiceRelationshipEntity : relationshipEntities){
                            Long contractId = invoiceRelationshipEntity.getContractId();
                            Long paymentId = invoiceRelationshipEntity.getPaymentId();
                            Double paymentInvoiceMoney = invoiceRelationshipEntity.getMoney();
                            InvoiceUtil.checkPaymentOrSheetInvoiceAmountHandle(contractReadyInvoiceMoneyMap,contractTotalInvoiceMoneyMap,paymentOrSheetReadyInvoiceMoneyMap,paymentOrSheetTotalInvoiceMoneyMap,contractId,paymentId,paymentInvoiceMoney,XbbRefTypeEnum.INVOICE.getCode(),PaymentRelationshipEnum.PAYMENT.getCode(),false,false);
                        }
                    }else {
                        if (Objects.equals(corpid,"ding14406b7cee552f61")){
                            LOGGER.warn("当前是回款单合并开票，amountDetail:{},contractReadyInvoiceMoneyMap:{},contractTotalInvoiceMoneyMap:{},paymentOrSheetReadyInvoiceMoneyMap:{},paymentOrSheetTotalInvoiceMoneyMap：{}"
                                    ,amountDetail,contractReadyInvoiceMoneyMap,contractTotalInvoiceMoneyMap,paymentOrSheetReadyInvoiceMoneyMap
                                    ,paymentOrSheetTotalInvoiceMoneyMap);
                        }
                        for(int i=0;i<amountDetail.size();i++){
                            JSONObject amountObject = amountDetail.getJSONObject(i);
                            JSONObject contractObject = amountObject.getJSONArray(InvoiceConstant.CONTRACT).getJSONObject(0);
                            JSONObject paymentObject = amountObject.getJSONArray(InvoiceConstant.PAYMENT).getJSONObject(0);
                            Long contractId = contractObject.getLong(BasicConstant.ID);
                            Long paymentId = paymentObject.getLong(BasicConstant.ID);
                            Double paymentInvoiceMoney = amountObject.getDouble(InvoiceConstant.INVOICE_AMOUNT);
                            InvoiceUtil.checkPaymentOrSheetInvoiceAmountHandle(contractReadyInvoiceMoneyMap,contractTotalInvoiceMoneyMap,paymentOrSheetReadyInvoiceMoneyMap,paymentOrSheetTotalInvoiceMoneyMap,contractId,paymentId,paymentInvoiceMoney,XbbRefTypeEnum.INVOICE.getCode(),PaymentRelationshipEnum.PAYMENT.getCode(),false,false);
                        }
                    }
                }
            }else if(BasicConstant.PAYMENTSHEET.equals(type)){
                //新增编辑 回款合并开票
                if (InvoiceConstant.EDIT.equals(operation)) {
                    param.put("invoiceIdNot", invoiceId);
                }
                List<Long> paymentSheetIds = null;
                List<Long> contractIds = null;
                int paymentSheetIdNum = 0;
                if(relationIdIn.get(InvoiceConstant.PAYMENT_SHEET_ID) instanceof List){
                    paymentSheetIds = (List<Long>) relationIdIn.get(InvoiceConstant.PAYMENT_SHEET_ID);
                    param.put("paymentSheetIdIn",paymentSheetIds);
                    paymentSheetIdNum = paymentSheetIds.size();
                }
                if(relationIdIn.get(InvoiceConstant.CONTRACT_ID) instanceof List){
                    contractIds = (List<Long>) relationIdIn.get(InvoiceConstant.CONTRACT_ID);
                }
                if(relationIdIn.get(InvoiceConstant.PAYMENT_SHEET_TOTAL_MONEY) instanceof Map){
                    paymentOrSheetTotalInvoiceMoneyMap = (Map<Long,Double>) relationIdIn.get(InvoiceConstant.PAYMENT_SHEET_TOTAL_MONEY);
                }
                if(relationIdIn.get(InvoiceConstant.CONTRACT_TOTAL_MONEY) instanceof Map){
                    contractTotalInvoiceMoneyMap = (Map<Long,Double>) relationIdIn.get(InvoiceConstant.CONTRACT_TOTAL_MONEY);
                }

                //获取已开的发票金额
                param.remove("paymentSheetIdIn");
                if(!isPrePaymentSheet) {
                    param.put("contractIdIn", contractIds);
                    getRefIdAndAmount(param,contractReadyInvoiceMoneyMap,InvoiceEnum.CONTRACT_ID);
                }
                param.put("paymentSheetIdIn",paymentSheetIds);
                getRefIdAndAmount(param,paymentOrSheetReadyInvoiceMoneyMap,InvoiceEnum.PAYMENT_SHEET_ID);

                if(Objects.equals(isImport,BasicConstant.ONE)){
                    //去掉之前的id
                    getCountInvoice(param,relationIdIn,invoiceMoney,InvoiceConstant.PAYMENT_SHEET_TOTAL_MONEY,isCover);
                }else{
                    if(Objects.equals(isRestore, BasicConstant.ONE)){
                        param.remove("invoiceIdNot");
                        param.put("invoiceId",invoiceId);
                        //作废后还原逻辑，去数据库取金额明细
                        param.put(ParameterConstant.IS_CANCEL, BasicConstant.ONE);
                        List<InvoiceRelationshipEntity> relationshipEntities = invoiceRelationshipModel.findEntitys(param);
                        for(InvoiceRelationshipEntity invoiceRelationshipEntity : relationshipEntities){
                            Long contractId = invoiceRelationshipEntity.getContractId();
                            Long paymentSheetId = invoiceRelationshipEntity.getPaymentSheetId();
                            Double paymentSheetInvoiceMoney = invoiceRelationshipEntity.getMoney();
                            InvoiceUtil.checkPaymentOrSheetInvoiceAmountHandle(contractReadyInvoiceMoneyMap,contractTotalInvoiceMoneyMap,paymentOrSheetReadyInvoiceMoneyMap,paymentOrSheetTotalInvoiceMoneyMap,contractId,paymentSheetId,paymentSheetInvoiceMoney,XbbRefTypeEnum.INVOICE.getCode(),PaymentRelationshipEnum.PAYMENT_SHEET.getCode(),isPrePaymentSheet,isPrePaymentSheetUnion);
                        }
                    }else {
                        for (int i = 0; i < amountDetail.size(); i++) {
                            JSONObject amountObject = amountDetail.getJSONObject(i);
                            Long contractId = 0L;
                            if(!isPrePaymentSheetUnion){
                                JSONObject contractObject = amountObject.getJSONArray(InvoiceConstant.CONTRACT).getJSONObject(0);
                                contractId = contractObject.getLong(BasicConstant.ID);
                            }
                            JSONObject paymentSheetObject = amountObject.getJSONArray(InvoiceConstant.PAYMENTSHEET).getJSONObject(0);
                            Long paymentSheetId = paymentSheetObject.getLong(BasicConstant.ID);
                            Double paymentSheetInvoiceMoney = amountObject.getDouble(InvoiceConstant.INVOICE_AMOUNT);
                            InvoiceUtil.checkPaymentOrSheetInvoiceAmountHandle(contractReadyInvoiceMoneyMap,contractTotalInvoiceMoneyMap,paymentOrSheetReadyInvoiceMoneyMap,paymentOrSheetTotalInvoiceMoneyMap,contractId,paymentSheetId,paymentSheetInvoiceMoney,XbbRefTypeEnum.INVOICE.getCode(),PaymentRelationshipEnum.PAYMENT_SHEET.getCode(),isPrePaymentSheet,isPrePaymentSheetUnion);
                        }
                    }
                }
            }
        }
    }

    private void getRefIdAndAmount(Map<String,Object> param,Map<Long,Double> readyInvoiceMoneyMap,InvoiceEnum invoiceEnum){
        List<InvoiceRelationshipEntity> contractSumList = invoiceRelationshipModel.findEntitys(param);
        Long refId = 0L;
        for(InvoiceRelationshipEntity invoiceRelationshipEntity : contractSumList){
            if(Objects.equals(invoiceEnum,InvoiceEnum.CONTRACT_ID)){
                if(Objects.nonNull(invoiceRelationshipEntity.getContractId())){
                    refId = invoiceRelationshipEntity.getContractId();
                }
            }else if(Objects.equals(invoiceEnum,InvoiceEnum.PAYMENT_ID)){
                if(Objects.nonNull(invoiceRelationshipEntity.getPaymentId())){
                    refId = invoiceRelationshipEntity.getPaymentId();
                }
            }else if(Objects.equals(invoiceEnum,InvoiceEnum.PAYMENT_SHEET_ID)){
                if(Objects.nonNull(invoiceRelationshipEntity.getPaymentSheetId())){
                    refId = invoiceRelationshipEntity.getPaymentSheetId();
                }
            }
            if(readyInvoiceMoneyMap.containsKey(refId)){
                readyInvoiceMoneyMap.put(refId,readyInvoiceMoneyMap.get(refId) + invoiceRelationshipEntity.getMoney());
            }else {
                readyInvoiceMoneyMap.put(refId,invoiceRelationshipEntity.getMoney());
            }
        }
    }

    /**
     * 判断操作类型和是否合并开票
     *
     * @param relationIdIn map
     * @param invoiceId    发票id
     * @return map
     */
    private Map<String, Object> judgeOperationAndMerge(Map<String, Object> relationIdIn, Long invoiceId) {
        Integer contractNum = (Integer) relationIdIn.get("contractNum");
        Integer paymentNum = (Integer) relationIdIn.get("paymentNum");
        Integer paymentSheetNum = (Integer) relationIdIn.get("paymentSheetNum");
        Map<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 操作类型
        String operation = "";
        // 是否合并开票
        boolean isMerge = false;
        if (invoiceId == 0L) {
            //新建的情况
            operation = InvoiceConstant.NEW;
            if (contractNum > BasicConstant.ONE || paymentNum > BasicConstant.ONE
                    || paymentSheetNum > BasicConstant.ONE) {
                // 根据新建修改的合同或回款数判断是否为合并开票
                isMerge = true;
            }
        } else if (invoiceId > 0L) {
            operation = InvoiceConstant.EDIT;
            if (contractNum > BasicConstant.ONE || paymentNum > BasicConstant.ONE || paymentSheetNum > BasicConstant.ONE) {
                // 根据新建修改的合同或回款数判断是否为合并开票
                isMerge = true;
            }
        }

        if(contractNum>0){
            String type = BasicConstant.CONTRACT;
            if(paymentNum>0){
                type = BasicConstant.PAYMENT;
            }
            if(paymentSheetNum>0){
                type = BasicConstant.PAYMENTSHEET;
            }
            map.put("type",type);
        }else if(paymentSheetNum >0){
            map.put("type",BasicConstant.PAYMENTSHEET);
        }
        map.put("operation", operation);
        map.put("isMerge", isMerge);
        return map;
    }

    private void getCountInvoice(Map<String, Object> param,Map<String,Object> relationIdIn, Double invoiceMoney, String key, Integer isCover) throws XbbException{
        //导入不用再去判断合同有没有开过票,直接去校验金额
        if(Objects.equals(key,InvoiceConstant.PAYMENT_TOTAL_MONEY)){
            param.remove("paymentIdIn");
        }
        if(Objects.equals(key,InvoiceConstant.PAYMENT_SHEET_TOTAL_MONEY)){
            param.remove("paymentSheetIdIn");
        }
        Double contractMoney = MoneyUtil.parseDouble(relationIdIn.get(InvoiceConstant.CONTRACT_MONEY));
        Double paymentMoney = MoneyUtil.parseDouble(relationIdIn.get(InvoiceConstant.PAYMENT_MONEY));
        Double paymentSheetMoney = MoneyUtil.parseDouble(relationIdIn.get(InvoiceConstant.PAYMENT_SHEET_MONEY));
        if(Objects.equals(key,InvoiceConstant.CONTRACT_TOTAL_MONEY)) {
            if (invoiceMoney > contractMoney) {
                throw new XbbException(InvoiceErrorCodeEnum.APT_ERROR_216001);
            }
            commonCheckContractInvoiceAmount(relationIdIn,invoiceMoney,isCover,param,contractMoney);
        }else if(Objects.equals(key,InvoiceConstant.PAYMENT_TOTAL_MONEY)){
            if (invoiceMoney > paymentMoney) {
                throw new XbbException(InvoiceErrorCodeEnum.APT_ERROR_216002);
            }
            //合并开票时去效验一下合同的金额
            commonCheckContractInvoiceAmount(relationIdIn,invoiceMoney,isCover,param,contractMoney);
        }else if(Objects.equals(key,InvoiceConstant.PAYMENT_SHEET_TOTAL_MONEY)){
            if (invoiceMoney > paymentSheetMoney) {
                throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216022);
            }
            commonCheckContractInvoiceAmount(relationIdIn,invoiceMoney,isCover,param,contractMoney);
        }
        if(Objects.equals(key,InvoiceConstant.CONTRACT_TOTAL_MONEY)) {
            if (invoiceMoney < contractMoney) {
                throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216030);
            }
        }else if(Objects.equals(key,InvoiceConstant.PAYMENT_TOTAL_MONEY)){
            if (invoiceMoney < paymentMoney) {
                throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216031);
            }
        }else if(Objects.equals(key,InvoiceConstant.PAYMENT_SHEET_TOTAL_MONEY)){
            if (invoiceMoney < paymentSheetMoney) {
                throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216032);
            }
        }
    }

    public Map<Long, Double> getRedTotalMoneyByIdIn(List<Long> originIdIn,List<Long> negIdIn, String corpid) throws XbbException {
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termsQuery(StringConstant.JSON_DATA + StringConstant.POINT + InvoiceEnum.ORIGIN_ID.getAttr(), originIdIn));
        boolQueryBuilder.filter(termsQuery(FieldTypeEnum.FLOW_STATUS.getAlias(), Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType())));
        boolQueryBuilder.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD , corpid));
        boolQueryBuilder.filter(termQuery(ParameterConstant.DEL, DelEnum.NORMAL.getDel()));
        if (CollectionsUtil.isNotEmpty(negIdIn)){
            boolQueryBuilder.filter(boolQuery().mustNot(termsQuery(FieldTypeEnum.DATAID.getAlias(), negIdIn)));
        }
        List<String> fieldList = new ArrayList<>();
        fieldList.add(InvoiceEnum.getAttrConnectData(InvoiceEnum.ORIGIN_ID));
        fieldList.add(InvoiceEnum.getAttrConnectData(InvoiceEnum.TOTAL_MONEY));
        List<PaasFormDataEntityExt> originInvoiceList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_INVOICE, boolQueryBuilder, PaasFormDataEntityExt.class, fieldList);
        Map<Long, Double> redMoneyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Long originId;
        Double money;
        for (PaasFormDataEntityExt paasFormDataEntityExt : originInvoiceList) {
            originId = FastJsonHelper.getLongOrDefaultFromFormData(paasFormDataEntityExt.getData(), InvoiceEnum.ORIGIN_ID.getAttr(), 0L);
            money = getDoubleOrDefaultFromFormData(paasFormDataEntityExt.getData(), InvoiceEnum.TOTAL_MONEY.getAttr(), 0D);
            if (redMoneyMap.containsKey(originId)) {
                money = redMoneyMap.get(originId) + money;
            }
            redMoneyMap.put(originId, money);
        }
        return redMoneyMap;
    }
    /**
     * 导入时效验合同的金额
     * @param relationIdIn
     * @param invoiceMoney
     * @throws XbbException
     */
    private void commonCheckContractInvoiceAmount(Map<String,Object> relationIdIn,Double invoiceMoney,Integer isCover,Map<String,Object> param,Double contractAmount) throws XbbException{
        Double contractUnInvoiceMoney = 0D;
        try {
            if(Objects.equals(isCover,BasicConstant.ONE)){
                double contractReadyInvoiceMoney = 0D;
                double contractTotalInvoiceMoney = contractAmount;
                List<InvoiceRelationshipEntity> invoiceRelationshipEntities = invoiceRelationshipModel.findEntitys(param);
                Set<Long> originIdList = new HashSet<>();
                if(CollectionsUtil.isNotEmpty(invoiceRelationshipEntities)) {
                    for (InvoiceRelationshipEntity invoiceRelationshipEntity : invoiceRelationshipEntities) {
                        contractReadyInvoiceMoney = Arith.add(contractReadyInvoiceMoney, invoiceRelationshipEntity.getMoney());
                        originIdList.add(invoiceRelationshipEntity.getInvoiceId());
                    }
                }
                String corpid = (String)param.getOrDefault("corpid","0");
                Map<Long, Double> redInvoiceMap = getRedTotalMoneyByIdIn(new ArrayList<Long>(originIdList),null,corpid);
                List<Double> contractRedInvoiceMoneyList= new ArrayList<>(redInvoiceMap.values());
                for (Double aDouble : contractRedInvoiceMoneyList) {
                    contractReadyInvoiceMoney = Arith.add(contractReadyInvoiceMoney,aDouble);
                }
                contractUnInvoiceMoney = Arith.sub(contractTotalInvoiceMoney,contractReadyInvoiceMoney);
            }else {
                Map<Long,Double> contractUnInvoiceMoneyMap = (Map<Long, Double>) relationIdIn.get(InvoiceConstant.CONTRACT_UN_INVOICE_MONEY);
                List<Double> contractUnInvoiceMoneyList= new ArrayList<>(contractUnInvoiceMoneyMap.values());
                for (Double aDouble : contractUnInvoiceMoneyList) {
                    contractUnInvoiceMoney = Arith.add(contractUnInvoiceMoney,aDouble);
                }
            }
        } catch (Exception e) {
            LOGGER.error("",e);
        }
        if(invoiceMoney > contractUnInvoiceMoney){
            throw new XbbException(InvoiceErrorCodeEnum.APT_ERROR_216001);
        }
    }

    public Double getRedTotalMoneyByEdit(Long originId, String corpid,Long editInvoiceId) throws XbbException {
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put(ParameterConstant.CORPID, corpid);
        param.put(ParameterConstant.FLOW_STATUS_IN, Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType()));
        param.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        List<PaasFormDataEntityExt> paasFormDataEntityExts = paasEsModel.selectByOneCondition(RedundantTemplateTypeEnum.INVOICE.getCode(), InvoiceEnum.ORIGIN_ID.getAttr(), originId, param, IndexTypeEnum.IDX_SAAS_INVOICE);
        Double redTotalMoney = 0D;
        for (PaasFormDataEntityExt paasFormDataEntityExt : paasFormDataEntityExts) {
            if(Objects.equals(editInvoiceId,paasFormDataEntityExt.getId())){
                continue;
            }
            Double money = getDoubleFromFormData(paasFormDataEntityExt.getData(), InvoiceEnum.TOTAL_MONEY.getAttr());
            if (money == null) {
                money = 0D;
            }
            redTotalMoney += money;
        }
        return redTotalMoney;
    }
}
